home *** CD-ROM | disk | FTP | other *** search
/ TeX 1995 July / TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO / dviware / ln03 / thomas / pk.c < prev    next >
C/C++ Source or Header  |  1990-10-01  |  33KB  |  1,097 lines

  1. /* Copyright (C) 1987, Matt Thomas
  2.  
  3. Here starts the code for processing PK files.  It was designed to be able
  4. to run on any byte addressable CPU, but primarily the VAX.  If you wonder 
  5. why I did something the way I did, think of the machine code it would produce.
  6. For instance, I AND instead MOD if I would be MODing by a power of two.  In 
  7. other words, I make life for compiler optimizer.  I make one assumption.  This 
  8. code will always be run on a machine with a large address space and an infinite
  9. heap (PDP-11s are out of luck).
  10.  
  11. PK files are big-endian but the VAX [and the LN03] are little endian.  So
  12. everything is backwards!  So we have reverse things as we go.  Keep this in
  13. mind as you study the code below.  Also a copy of PKtoPX.WEB is very useful
  14. to have nearby while studying this code. 
  15.  
  16. This code is divided into three parts, the first is the generic part.  This
  17. is where I define by module global variables, macro, includes files, etc.
  18. The second part is font hadnling code.  And the the third id the glyph
  19. handling code.  Each part can be easily found in a listing by looking for
  20. either GENERIC, FONTS, or GLYPHS in large block letters.
  21.  
  22. If you find any bugs in following code, please send me a mail message
  23. telling me where I screwed up.  On the Easynet, use THEBAY::MTHOMAS.
  24. On USENET, try ...!ptsfa!ista!thomas.  On the Internet, use 
  25. ptsfa!ista!thomas@{sun.com,lll-crg.arpa,lll-lcc.arpa,ames.nasa.gov}  
  26.  
  27. Thanks,
  28. Matt Thomas
  29. PO BOX 121
  30. Rheem Valley, CA 94570.
  31. */
  32.  
  33. /***************************************************************************
  34. ****************************************************************************
  35.  
  36.  
  37.   GGGGGGGG  EEEEEEEEE  NN    NN  EEEEEEEE  RRRRRRRR    IIIIIIII    CCCCCCC
  38. GG          EE         NNN   NN  EE        RR      RR     II     CC       CC
  39. GG          EE         NNNN  NN  EE        RR      RR     II     CC
  40. GG    GG    EEEEE      NN NN NN  EEEEE     RRRRRRRR       II     CC
  41. GG      GG  EE         NN  NNNN  EE        RR    RR       II     CC
  42. GG      GG  EE         NN   NNN  EE        RR     RR      II     CC      CC
  43.   GGGGGG    EEEEEEEEE  NN    NN  EEEEEEEE  RR      RR  IIIIIIII    CCCCCC
  44.  
  45.  
  46. ***************************************************************************
  47. **************************************************************************/
  48. /*    I N C L U D E S        */
  49.  
  50. #ifdef vms
  51. #include stdio.h
  52. #include errno.h
  53. #include stat.h
  54. #else
  55. #include <stdio.h>
  56. #include <errno.h>
  57. #include <sys/types.h>
  58. #include <sys/stat.h>
  59. #endif
  60. #include "pk.h"
  61.  
  62. /*
  63. /*  Errno gets defined in different ways on different machines.
  64. /*  Under VMS and System V, it gets defined in errno.h but under
  65. /*  BSD 4.x you have declare it yourself.  Also we use strchr
  66. /*  instead of index (BSD version) so we conditionalize that here
  67. /*  too.
  68. */
  69. #ifdef  bsd4_2
  70. # define strchr index
  71. extern int errno;
  72. #endif
  73.  
  74.  
  75. /****************************************************
  76. *****************************************************
  77.  
  78.  
  79. FFFFFFFFF    OOOOOO    NN    NN  TTTTTTTT    SSSSSS
  80. FF         OO      OO  NNN   NN     TT     SS      SS
  81. FF         OO      OO  NNNN  NN     TT     SS
  82. FFFFFF     OO      OO  NN NN NN     TT       SSSSSS
  83. FF         OO      OO  NN  NNNN     TT             SS
  84. FF         OO      OO  NN   NNN     TT     SS      SS
  85. FF           OOOOOO    NN    NN     TT       SSSSSS
  86.  
  87.  
  88. *****************************************************
  89. ****************************************************/
  90.  
  91.  
  92. #ifdef ANSIC
  93. extern    PKFont *    PKLoadFont( char fontname, int magnification, int pixelsize );
  94. extern    void        PKTrimFont( PKFont *fontptr );
  95. extern    void        PKUnloadFont( PKFont *fontptr );
  96. static    float        PKAcutalFactor( int magnification );
  97. static    char *        PKGetFontFileName( char *fontname, int magnification, int pixelsize );
  98. static    PKFont *    PKReadFontPreamble( PKFont *fontptr );
  99. #else
  100. extern    PKFont *    PKLoadFont();
  101. extern    void        PKTrimFont();
  102. extern    void        PKUnloadFont();
  103. static    float        PKAcutalFactor();
  104. static    char *        PKGetFontFileName();
  105. static    PKFont *    PKReadFontPreamble();
  106. #endif
  107.  
  108. /*  This routine opens the PK file.  In addition for reasons of speed and
  109. efficency, it is easier and faster to malloc enough memory to store the
  110. entire PK file in memory than to read and seek as needed from the file. 
  111. So in this routine, not only do we open the PK file but we also completely 
  112. read it into the malloc'ed buffer.  We also read the preamble to verify
  113. the magnification and to get the font characterstics. */
  114.  
  115. PKFont *
  116. PKLoadFont( fontname, magnification, pixelsize )
  117. char *fontname;
  118. int magnification;
  119. int pixelsize;
  120. {
  121.     PKFont  *fontptr;
  122.     int i,j, pkf;
  123.     char *filespec;
  124.     struct stat stat_buf;
  125.  
  126.     PKerror[0] = '\0';
  127.  
  128.     filespec = PKGetFontFileName( fontname, magnification, pixelsize );
  129.     pkf = open(filespec,0);
  130.     if  (pkf == -1)  {
  131.     (void) strcpy( PKerror, filespec );
  132.     return(NULL);
  133.     }
  134.  
  135.     j = sizeof(PKFont) + strlen(fontname) + 1;
  136.     fontptr = (PKFont *) malloc( j );
  137.     if  (fontptr == NULL) {
  138.     sprintf( PKerror, "can't malloc %ld bytes for font structure", j );
  139.     close(pkf);
  140.     return(NULL);
  141.     }
  142.  
  143.     fontptr->fontname = ((char *) fontptr) + sizeof(PKFont);
  144.     strcpy( fontptr->fontname, fontname );
  145.  
  146.     fontptr->filespec = filespec;
  147.  
  148.     for ( i = 0; i <= PKMAXGLYPH; i++ ) {
  149.     fontptr->packed_glyphs[i] = NULL;
  150.     fontptr->unpacked_glyphs[i] = NULL;
  151.     }
  152.  
  153. /* Seek to the end of the file to determine the size of the 
  154. file, free the previously malloc'ed buffer, and then malloc 
  155. enough heap to save it in memory.  After that is done, seek 
  156. back to the beginning of the file, and read the contents
  157. into the just malloc'ed buffer.  KLUDGE ALERT!!!  Since fstat
  158. under VMS doesn't work across DECnet, we kludge around by just 
  159. allocating a buffer of 100KB and hope it's enough.  */
  160.  
  161.     i = fstat( pkf, &stat_buf );
  162.     if  (i < 0) {
  163. #ifdef  vms
  164.     if  (errno == ENXIO || errno == 0) {
  165.         register char *str = getenv("PKMAXFONTSIZE");
  166.         j = PKMAXFONTSIZE;
  167.         if  (str != NULL) {
  168.         j = atol(str);
  169.         if  (j < PKMAXFONTSIZE)
  170.             j = PKMAXFONTSIZE;
  171.         }
  172.         stat_buf.st_size = -1;
  173.         fontptr->fontsize = j;
  174.     } else {
  175. #endif
  176.         sprintf( PKerror, "fstat failed: errno = %d", errno );
  177.         close(pkf);
  178.         PKUnloadFont( fontptr );
  179.         return(NULL);
  180. #ifdef    vms
  181.     }
  182. #endif
  183.     } else {
  184.     fontptr -> fontsize = stat_buf.st_size;
  185.     }
  186.     fontptr -> fontstream = (unsigned char *) malloc( fontptr->fontsize );
  187.     if  (i < 0) {
  188.     sprintf( PKerror, "fstat failed: errno = %d", errno );
  189.     close(pkf);
  190.     PKUnloadFont( fontptr );
  191.     return(NULL);
  192.     }
  193.     fontptr -> fontsize = stat_buf.st_size;
  194.     fontptr -> fontstream = (unsigned char *) malloc( fontptr->fontsize );
  195.     if  (fontptr->fontstream == NULL) {
  196.     sprintf( PKerror, "can't malloc %ld bytes for file buffer", fontptr->fontsize );
  197.     close(pkf);
  198.     PKUnloadFont( fontptr );
  199.     return(NULL);
  200.     }
  201.  
  202. /* read the file into the just allocated memory buffer */
  203.  
  204.     i = 0;
  205.     do  {
  206.     j = read(pkf, fontptr->fontstream+i, fontptr->fontsize-i);
  207.     i += j;
  208.     }   while  ( j > 0 && i < fontptr->fontsize );
  209.  
  210.     if  (j < 0) {
  211.     strcpy(PKerror,"read error: errno = %d", errno);
  212.     close(pkf);
  213.     PKUnloadFont( fontptr );
  214.     return(NULL);
  215.     } else if (i < fontptr->fontsize && stat_buf.st_size != -1) {
  216.     sprintf( PKerror,
  217.         "error: premature EOF (%d of %d)", 
  218.         i, fontptr->fontsize);
  219.     close(pkf);
  220.     PKUnloadFont( fontptr );
  221.     return(NULL);
  222.     }
  223.     close(pkf);
  224.  
  225.     fontptr = PKReadFontPreamble( fontptr );
  226.     return (fontptr);
  227. }
  228.  
  229.  
  230. extern    void
  231. PKTrimFont( fontptr )
  232. PKFont    *fontptr;
  233. {
  234.     PKerror[0] = '\0';
  235.  
  236.     if  (fontptr->fontstream != NULL)
  237.     free( fontptr->fontstream );
  238.     fontptr->fontstream = NULL;
  239.  
  240.     return;
  241. }
  242.  
  243. /*  This routines frees all storage associated with a font. */
  244.  
  245. extern    void
  246. PKUnloadFont( fontptr )
  247. PKFont    *fontptr;
  248. {
  249.     int idx;
  250.  
  251.     PKerror[0] = '\0';
  252.  
  253.     for( idx = 0; idx <= PKMAXGLYPH; idx ++ )
  254.     PKFreeGlyph( fontptr->unpacked_glyphs[idx] );
  255.  
  256.     if  (fontptr->filespec != NULL)
  257.     free( fontptr->filespec );
  258.  
  259.     if  (fontptr->fontstream != NULL)
  260.     free( fontptr->fontstream );
  261.  
  262.     return;
  263. }
  264.  
  265.  
  266. /* This routine is taken from dvi2ps and is used to get around rounding
  267. errors in the integer form of the magnification. */
  268.  
  269. static    float
  270. PKActualFactor(unmodsize)
  271. int unmodsize;  /* actually factor * 1000 */
  272. {
  273.     float realsize;    /* the actual magnification factor */
  274.  
  275.     realsize = (float)unmodsize / 1000.0;
  276.     /* a real hack to correct for rounding in some cases--rkf */
  277.     if(unmodsize==1095) realsize = 1.095445;    /*stephalf*/
  278.     else if(unmodsize==1315) realsize=1.314534;    /*stepihalf*/
  279.     else if(unmodsize==2074) realsize=2.0736;    /*stepiv*/
  280.     else if(unmodsize==2488) realsize=2.48832;  /*stepv*/
  281.     else if(unmodsize==2986) realsize=2.985984;    /*stepiv*/
  282.     /* the remaining magnification steps are represented with sufficient
  283.        accuracy already */
  284.     return(realsize);
  285. }
  286.  
  287. /* This routine constructs the file name from supplied fontname and
  288. magnification.  If the magnification is non-positive, then the font name
  289. is considered to be the filename.  When not running under VMS, if colons
  290. are present in the TEXPKDIR variable, then each directory is searched for
  291. the PK file until eith no more directories or a file is found.  */
  292.  
  293. static    char    *
  294. PKGetFontFileName( fontname, magnification, pixelsize )
  295. char    *fontname;
  296. int    magnification;
  297. int    pixelsize;
  298. {
  299.     char *pathlist, *pp, *pkdir;
  300.     char *filespec = (char *) malloc( strlen(fontname) + 8 );
  301.     char *fullspec = (char *) malloc( PKFILESPECLENGTH + 1 );
  302.  
  303.     strcpy(filespec, fontname);
  304.     if  (magnification > 0) {
  305.     int fext = (float) pixelsize * 
  306.             (float) PKActualFactor(magnification) + 0.5;
  307.     sprintf( &filespec[strlen(filespec)], ".%dpk\0", fext);
  308.     }
  309.  
  310. #ifdef vms
  311.     strcpy( PKerror, filespec );
  312.     pathlist = "tex$pkdir:";
  313.     sprintf( fullspec, "%s%s", pathlist, filespec );
  314. #else
  315.     pkdir = (char *) getenv("TEXPKDIR");
  316.     if  (pkdir == NULL)
  317.     pkdir = "/usr/lib/tex/pkdir";
  318.     pathlist = (char *) malloc( strlen(pkdir) + 1 );
  319.     strcpy( pathlist, pkdir );
  320.     pkdir = pathlist;
  321.     while (1) {
  322.     pp = (char *) strchr(pathlist, ':');
  323.     if (pp != NULL)
  324.         *pp = '\0';
  325.     sprintf( fullspec, "%s/%s", pathlist, filespec );
  326.     if (0 <= access(fullspec, 4)) {
  327.         strcpy( PKerror, filespec );
  328.         break;
  329.     }
  330.     if (pp != NULL)
  331.         pathlist = pp + 1;
  332.     strcpy( PKerror, fullspec );
  333.     if (pp == NULL)
  334.         break;
  335.     }
  336.     free( pkdir );
  337. #endif
  338.     free( filespec );
  339.     return(fullspec);
  340. }
  341.  
  342.  
  343. /* This routine reads the preamble of the PK file and verifies it's 
  344. consistency and reads the font's characteristics into the PKFont
  345. structure pointed by fontptr.  If an error is found Pkerror will contain
  346. an error message, the font is unloaded, and a NULL will be returned. */
  347.  
  348. static    PKFont *
  349. PKReadFontPreamble( fontptr )
  350. register PKFont    *fontptr;
  351. {
  352.  
  353.     fontptr->fontidx = fontptr->fontstream;
  354.     if  (Get_8Bit_Unsigned(fontptr->fontidx) != PK_PRE) {
  355.     sprintf(PKerror, "error: bad PK file (no preamble)");
  356.     PKUnloadFont( fontptr );
  357.     return(NULL);
  358.     }
  359.     if  (Get_8Bit_Unsigned(fontptr->fontidx) != PK_ID) {
  360.     sprintf(PKerror, "bad PK file (invalid id %d)",
  361.         fontptr->fontstream[1] );
  362.     PKUnloadFont( fontptr );
  363.     return( NULL );
  364.     }
  365.  
  366. /*  Calculate the true magnification. */
  367.  
  368.     /* skip the comment */
  369.     fontptr->fontidx += Get_8Bit_Unsigned(fontptr->fontidx);
  370.  
  371.     fontptr->design_size    = Get_32Bit_Unsigned(fontptr->fontidx);
  372.     fontptr->checksum        = Get_32Bit_Unsigned(fontptr->fontidx);
  373.     fontptr->v_pixels_per_point = Get_32Bit_Unsigned(fontptr->fontidx);
  374.     fontptr->h_pixels_per_point = Get_32Bit_Unsigned(fontptr->fontidx);
  375.  
  376.     fontptr->magnification = 5.0 * (float) fontptr->h_pixels_per_point
  377.         * 72.27 / 65536.0 + 0.5;
  378.  
  379.     return(fontptr);
  380. }
  381.  
  382. /*********************************************************************
  383. **********************************************************************
  384.  
  385.  
  386.  
  387.   GGGGGGGG   LL        YY      YY  PPPPPPPP    HH      HH    SSSSSSS
  388. GG           LL         YY    YY   PP      PP  HH      HH  SS       SS
  389. GG           LL           YYYY     PP      PP  HH      HH  SS
  390. GG   GGG     LL            YY      PPPPPPPP    HHHHHHHHHH    SSSSSS
  391. GG      GG   LL            YY      PP          HH      HH          SS
  392. GG      GG   LL            YY      PP          HH      HH  SS      SS
  393.   GGGGGG     LLLLLLLLLL    YY      PP          HH      HH    SSSSSS
  394.  
  395.  
  396. *********************************************************************
  397. ********************************************************************/
  398.  
  399. /*
  400. /*    Get a specific glyph from the PK file
  401. */
  402. extern    PKGlyph *    PKGetGlyph();
  403.  
  404. /*
  405. /*    Get a specific glyph from the PK file, analyze it's preamble,
  406. /*    but DON'T unpack it.
  407. */
  408. extern    PKGlyph *    PKGetGlyphInfo();
  409.  
  410. /*
  411. /*    get the next glyph from the PK file
  412. */
  413. extern    PKGlyph *    PKGetNextGlyph();
  414.  
  415. /*
  416. /*    Free storage associated with a glyph.
  417. */
  418. extern    void        PKFreeGlyph();
  419.  
  420. /*
  421. /*    Find the glyph in the PK file and return a pointer to it
  422. */
  423. static    unsigned char *    PKScanForGlyph();
  424.  
  425. /*
  426. /*    Skip commands in the PK file stream.
  427. */
  428. static    unsigned char *    PKSkipSpecials();
  429.  
  430. /*
  431. /*    decodes a glyph requested by 1 or 2
  432. */
  433. static    PKGlyph *    PKDecodeGlyph();
  434.  
  435. /*
  436. /*    Read the character preamble and returna a pointer
  437. /*    to a PKGlyph structure with the requested information.
  438. */
  439. static    PKGlyph *    PKReadPreamble();
  440.  
  441. /*
  442. /*    Unpack run-length encoded rasters
  443. */
  444. static    void        PKUnpackRasters();
  445.  
  446. /*
  447. /*    Copy the unencoded raster format
  448. */
  449. static    void        PKCopyRasters();
  450.  
  451.  
  452. /* This routine retrives a specific glyph from the supplied font. */
  453.  
  454. PKGlyph    *
  455. PKGetGlyph( fontptr, glyph_id )
  456. PKFont    *fontptr;
  457. int    glyph_id;
  458. {
  459.     PKGlyph  *glyphptr;
  460.  
  461.     PKerror[0] = '\0';
  462.  
  463.     if  (glyph_id > PKMAXGLYPH || glyph_id < 0) {
  464.     sprintf( PKerror, 
  465.         "invalid glyph (%d): must be in the range from 0 to %ld",
  466.         glyph_id, PKMAXGLYPH );
  467.     return(NULL);
  468.     }
  469.  
  470.     if  (fontptr->unpacked_glyphs[glyph_id] == NULL)
  471.     glyphptr = PKReadPreamble( PKScanForGlyph( fontptr, glyph_id ) );
  472.     else
  473.     glyphptr = fontptr->unpacked_glyphs[glyph_id];
  474.  
  475.     if  (glyphptr != NULL) {
  476.     glyphptr->fontptr = fontptr;
  477.     glyphptr = PKDecodeGlyph( glyphptr );
  478.     (fontptr->unpacked_glyphs)[glyph_id] = glyphptr;
  479.     }
  480.  
  481.     if  (glyphptr == NULL) {
  482.     sprintf( PKerror, "glyph %d not in file", glyph_id );
  483.     }
  484.  
  485.    return(glyphptr);
  486. }
  487.  
  488.  
  489. /* This routine retrives a specific glyph from the supplied font. */
  490.  
  491. PKGlyph    *
  492. PKGetGlyphInfo( fontptr, glyph_id )
  493. PKFont    *fontptr;
  494. int    glyph_id;
  495. {
  496.     PKGlyph  *glyphptr;
  497.  
  498.     PKerror[0] = '\0';
  499.  
  500.     if  (glyph_id > PKMAXGLYPH || glyph_id < 0) {
  501.     sprintf( PKerror, 
  502.         "invalid glyph (%d): must be in the range from 0 to %ld",
  503.         glyph_id, PKMAXGLYPH );
  504.     return(NULL);
  505.     }
  506.  
  507.     if  (fontptr->unpacked_glyphs[glyph_id] == NULL)
  508.     glyphptr = PKReadPreamble( PKScanForGlyph( fontptr, glyph_id ) );
  509.     else
  510.     glyphptr = fontptr->unpacked_glyphs[glyph_id];
  511.  
  512.     if  (glyphptr != NULL) {
  513.     glyphptr->fontptr = fontptr;
  514.     (fontptr->unpacked_glyphs)[glyph_id] = glyphptr;
  515.     }
  516.  
  517.     if  (glyphptr == NULL) {
  518.     sprintf( PKerror, "glyph %d not in file", glyph_id );
  519.     }
  520.  
  521.     return(glyphptr);
  522. }
  523.  
  524.  
  525. PKGlyph    *
  526. PKGetNextGlyph( fontptr )
  527. PKFont    *fontptr;
  528. {
  529.     PKGlyph *glyphptr;
  530.  
  531.     PKerror[0] = '\0';
  532.  
  533.     if (fontptr == NULL) {
  534.     sprintf( PKerror, "font not defined" );
  535.     return(NULL);
  536.     }
  537.  
  538.     glyphptr = PKReadPreamble( PKScanForGlyph( fontptr, -1 ) );
  539.  
  540.     if  (glyphptr != NULL) {
  541.     glyphptr->fontptr = fontptr;
  542.     glyphptr = PKDecodeGlyph( glyphptr );
  543.     fontptr->unpacked_glyphs[glyphptr->glyph_id] = glyphptr;
  544.     }
  545.  
  546.     return(glyphptr);
  547. }
  548.  
  549.  
  550. void
  551. PKFreeGlyph( glyphptr )
  552. PKGlyph *glyphptr;
  553. {
  554.     if  (glyphptr == NULL)
  555.     return;
  556.     glyphptr->fontptr->unpacked_glyphs[glyphptr->glyph_id] = NULL;
  557.  
  558.     if  (glyphptr->rasters != NULL)
  559.     free(glyphptr->rasters);
  560.  
  561.     free(glyphptr);
  562. }
  563.  
  564. /* Since a PK file does not a directory as does a PXL file we must scan
  565. the PK file to find a glyph.  Also since a PK file may not be sorted in
  566. ascending order, we may have to scan the entire file.  To save time on
  567. scanning for later glyphs, we remeber the locations of the glyphs we
  568. enounter.  
  569.  
  570. We scan the PK file without unpacking because each character preamble
  571. contains the length of packed glyph.  Hence we need only read enough
  572. to obtain the packet_length and the glyph_id.  
  573.  
  574. [[This would be a good time to get PXtoPK.WEB.]]
  575.  
  576. There are three types of character preambles in a PK file: short, extended
  577. short, and long.  The first byte of every preamble in called the flag_byte.
  578. It contains three fields, only one of which is used in this routine.  It is
  579. contained in bits 0-2 (the lower three bits) and indicates the type of the
  580. preamble.  Values 0-3 indicate a short preamble, 4-6 a extended short, and 7
  581. a long.
  582.  
  583. All the preambles (at least the part we char about here) have three parts:
  584. the flag_byte [[flag]], the packet_length [[pl]], and the glyph_id [[cc]].
  585.  
  586. In a short preamble, both the packet_length and the glyph_id are unsigned
  587. bytes.  Also the bottom two bits of the flag_byte are multipled by 256 and
  588. the result is added to get the true packet length.
  589.  
  590. In an extended short preamble, the packet_length is a two byte unsigned word
  591. while the glyph_id is an unsigned char.  The bottom two bits of the flag_byte
  592. should be multiplied by 65536 and added to packet_length.
  593.  
  594. In a long preamble, both the packet_length and the glyph_id are four byte
  595. integers.
  596.  
  597. That's all for now.
  598. */
  599.  
  600. static unsigned char *
  601. PKScanForGlyph( fontptr, target )
  602. register PKFont *fontptr;
  603. int target;
  604. {
  605.     unsigned char flag_byte, *glyphptr = NULL;
  606.     register unsigned char *streamptr;
  607.     int packet_length, glyph_id;
  608.  
  609.     /*
  610.     /*  If we have done a PKTrimFont, don't scan.
  611.     */
  612.     if  (fontptr->fontstream == NULL)
  613.     return(NULL);
  614.  
  615.     /*
  616.     /*  See if we have previously scanned it.  If so,
  617.     /*  return a pointer to it.  Othwise, search for it.
  618.     */
  619.     if  (target != -1) {
  620.     glyphptr = fontptr->packed_glyphs[ target ];
  621.     if  (glyphptr != NULL) {
  622.         return(glyphptr);
  623.     }
  624.     }
  625.  
  626.     streamptr = fontptr->fontidx;
  627.     do  {
  628.     flag_byte = *streamptr;
  629.     if (flag_byte >= 240) {
  630.         if  (flag_byte == PK_POST) {
  631.         sprintf( PKerror, "no more glyphs" );
  632.         return(NULL);
  633.         }
  634.         streamptr = PKSkipSpecials( flag_byte, ++streamptr );
  635.         continue;
  636.     }
  637.  
  638. /* Decode the character preambles to obtain packet lengths and the id of the
  639. character. */
  640.  
  641.     glyphptr = streamptr++;
  642.     flag_byte &= 0x07;
  643.     if  (flag_byte < 4) {
  644.         packet_length = Get_8Bit_Unsigned( streamptr );
  645.         if  (flag_byte > 0)
  646.         packet_length += flag_byte * 256;
  647.         glyph_id = Get_8Bit_Unsigned( streamptr );
  648.     } else if (flag_byte < 7) {
  649.         packet_length = Get_16Bit_Unsigned(streamptr);
  650.         if  ((flag_byte -= 4) > 0)
  651.         packet_length += flag_byte * 65536;
  652.         glyph_id = Get_8Bit_Unsigned( streamptr );
  653.     } else {
  654.         packet_length = Get_32Bit_Unsigned(streamptr);
  655.         glyph_id = Get_32Bit_Unsigned(streamptr);
  656.     }
  657.  
  658. /* Save the glyph's location for later retrieval.  Hopefully this will save
  659. some CPU cycles.  Also note that glyphs don't have to be in ascending order
  660. in a PK file.  If a PK file happened to ordered such the most common
  661. characters are at the beginning, this could save a lot of time. */
  662.  
  663.     if  (fontptr->packed_glyphs[glyph_id] == NULL)  {
  664.         fontptr->packed_glyphs[glyph_id] = glyphptr ;
  665.     } else {
  666.         sprintf( PKerror,
  667.         "warning: duplicate glyph (%d) detected, ",
  668.         glyph_id);
  669.     }
  670.  
  671. /* [[Since we don't expand/decipher a packed glyph immediately, a corrupt PK
  672. file would give us major confusion.  (The packet lengths would be the
  673. killers) So we just assume the PK files are error-free.]] */
  674.  
  675.     streamptr += packet_length;
  676.  
  677. /* We have found what we are looking for, so exit the loop and decipjer it.
  678. Otherwise keep on looking.  */
  679.  
  680.     } while ((glyph_id != target) && (target != -1));
  681.  
  682.     fontptr->fontidx = streamptr;
  683.     if  (target == -1 || target == glyph_id) {
  684.     return(glyphptr);
  685.     } else {
  686.     return(NULL);
  687.     }
  688. }
  689.  
  690.  
  691. /* This routine skip commands that may be present in a PK file.  And in
  692. reality we treat them all as NOPs.  See the PKtoPX.WEB for what they are
  693. really used for.  */
  694.  
  695. static unsigned char *
  696. PKSkipSpecials( flag_byte, streamptr )
  697. unsigned char flag_byte, *streamptr;
  698. {
  699.     int i;
  700.     switch (flag_byte) {
  701.     case PK_XXX4: i += *streamptr++; i <<= 8;
  702.     case PK_XXX3: i += *streamptr++; i <<= 8;
  703.     case PK_XXX2: i += *streamptr++; i <<= 8;
  704.     case PK_XXX1: i += *streamptr++;
  705.         streamptr += i;
  706.         break;
  707.     case PK_YYY: streamptr += 4;
  708.         break;
  709.     case PK_NO_OP:
  710.         break;
  711.     default:
  712.         sprintf( PKerror, 
  713.         "warning: detected illegal command %d",
  714.         flag_byte );
  715.     }
  716.     return(streamptr);
  717. }
  718.  
  719.  
  720. /* This routine decodes a PK glyph and then return a pointer to a
  721. PKglyph structure (which all the information about the glyph).  Normally
  722. this routine is called by either PKGetGlyph or PKGetNextGlyph.  */
  723.  
  724. static PKGlyph *
  725. PKDecodeGlyph( glyphptr )
  726. PKGlyph *glyphptr;
  727. {
  728.     int bytes_per_row, raster_size, idx;
  729.  
  730.     if (glyphptr == NULL)
  731.     return(NULL);
  732.  
  733.     if (glyphptr->rasters != NULL)
  734.     return(glyphptr);
  735.  
  736.  
  737. /* Decode the character preample, in either short, extended short, or long
  738. format.  Now that the preamble is decoded, we can expand the packed rasters
  739. (only if they would take up at least one byte). */
  740.  
  741.     bytes_per_row = (glyphptr->width + 7) / 8;
  742.     raster_size = bytes_per_row * glyphptr->height + 1;
  743.     glyphptr->rasters = (unsigned char *) malloc( raster_size );
  744.  
  745.     for (idx = 0; idx < raster_size; idx++)
  746.     glyphptr->rasters[idx] = 0;
  747.  
  748.     if (glyphptr->height != 0 && glyphptr->width != 0) {
  749.     if (glyphptr->dyn_f < 14) {
  750.         PKUnpackRasters( glyphptr );
  751.     } else {
  752.         PKCopyRasters( glyphptr );
  753.     }
  754.     }
  755.  
  756.     return( glyphptr );
  757. }
  758.  
  759.  
  760. /* This routine reads the preamble for a character glyph in a PK file.
  761. Doing it by brute force in by faar the easiet way to do it, so that's how we
  762. do it.  The LET macro does away with a lot of drugde work.
  763.  
  764. [[Get your copy of PKtoPX.WEB again.]]
  765.  
  766. Back to preambles.  (see scan_for_glyph) preambles have more fields than
  767. just the packet_length and the glyph_id.  In addition, there are:
  768.  
  769.     dyn_f:        See unpack_rasters
  770.     black:        indicates initial run is black or white
  771.     tfm_width:    width of character in .FIXes (I think)
  772.     width:        width in pixels of minimum bound box for glyph
  773.     height:        height ....
  774.     hoffset:    horizontial offset to reference point (LLHC)
  775.     voffset:    vertical ...
  776.     hescapement:    horizonal escapement in 2^16 pixels
  777.     vescapement:    vertical ...
  778.  
  779. There are others but we don't use them.  dyn_f is from bits 4-7 of the
  780. flag_byte.  black is bit 3 of the flag_byte (useful only if dyn_f < 14).
  781.  
  782. All values are bytes in the short preamble except for tfm_width which is a 3
  783. byte integer.  In the extended short from, all values are 2 byte words
  784. except for tfm_width which, again, a 3 byte inetger.  In the long preamble,
  785. all fields are 4 byte integers.  All fields are unsigned except for hoffset
  786. and voffset which are always signed.
  787.  
  788. */
  789.  
  790. static PKGlyph *
  791. PKReadPreamble( streamptr )
  792. register unsigned char *streamptr;
  793. {
  794.     unsigned flag_byte, dyn_f, color, packet_length, glyph_id;
  795.     unsigned tfm_width, height, width, hescapement, vescapement;
  796.     int hoffset, voffset;
  797.  
  798.     flag_byte        = Get_8Bit_Unsigned(streamptr);
  799.     dyn_f        = (flag_byte >> 4);
  800.     color        = ((flag_byte & 0x08) != 0);
  801.     flag_byte        &= 0x07;
  802.  
  803.     if  (flag_byte < 4) {
  804.     packet_length    = Get_8Bit_Unsigned(streamptr);
  805.     glyph_id    = Get_8Bit_Unsigned(streamptr);
  806.     tfm_width    = Get_24Bit_Unsigned(streamptr);
  807.     hescapement    = Get_8Bit_Unsigned(streamptr) * 65536;
  808.     vescapement    = 0;
  809.     width        = Get_8Bit_Unsigned(streamptr);
  810.     height        = Get_8Bit_Unsigned(streamptr);
  811.     hoffset        = Get_8Bit_Signed(streamptr);
  812.     voffset        = Get_8Bit_Signed(streamptr);
  813.     } else if (flag_byte < 7) {
  814.     packet_length    = Get_16Bit_Unsigned(streamptr);
  815.     glyph_id    = Get_8Bit_Unsigned(streamptr);
  816.     tfm_width    = Get_24Bit_Unsigned(streamptr);
  817.     hescapement    = Get_16Bit_Unsigned(streamptr) * 65536;
  818.     vescapement    = 0;
  819.     width        = Get_16Bit_Unsigned(streamptr);
  820.     height        = Get_16Bit_Unsigned(streamptr);
  821.     hoffset        = Get_16Bit_Signed(streamptr);
  822.     voffset        = Get_16Bit_Signed(streamptr);
  823.     } else {
  824.     packet_length    = Get_32Bit_Unsigned(streamptr);
  825.     glyph_id    = Get_32Bit_Unsigned(streamptr);
  826.     tfm_width    = Get_32Bit_Unsigned(streamptr);
  827.     hescapement    = Get_32Bit_Unsigned(streamptr);
  828.     vescapement    = Get_32Bit_Unsigned(streamptr);
  829.     width        = Get_32Bit_Unsigned(streamptr);
  830.     height        = Get_32Bit_Unsigned(streamptr);
  831.     hoffset        = Get_32Bit_Signed(streamptr);
  832.     voffset        = Get_32Bit_Signed(streamptr);
  833.     }
  834.  
  835.     {    register PKGlyph *glyphptr;
  836.  
  837.     glyphptr = (PKGlyph *) malloc( sizeof(PKGlyph) );
  838.     if  (glyphptr == NULL) {
  839.         sprintf( PKerror, "can't malloc %ld bytes for a PKGlyph", 
  840.             sizeof(PKGlyph) );
  841.         return(NULL);
  842.     }
  843.     glyphptr->glyph_id = glyph_id;
  844.     glyphptr->rasters = NULL;
  845.     glyphptr->prasters = streamptr;
  846.     glyphptr->tfm_width = tfm_width;
  847.     glyphptr->width = width;
  848.     glyphptr->height = height;
  849.     glyphptr->h_offset = hoffset;
  850.     glyphptr->v_offset = voffset;
  851.     glyphptr->h_escapement = hescapement;
  852.     glyphptr->v_escapement = vescapement;
  853.     glyphptr->dyn_f = dyn_f;
  854.     glyphptr->color = color;
  855.  
  856.     return(glyphptr);
  857.     }
  858. }
  859.  
  860.  
  861. /* This routine decodes the packed rasters pointed to by glyphptr->prasters
  862. and places the unpacked rasters in the buffer pointed to by
  863. glyphptr->rasters.  Now if it were only that simple...
  864.  
  865. [[Got PKtoPX.WEB in hand?]]
  866.  
  867. This routine uses a companion functon, PKGetRunCount, to obtain the run
  868. counts.
  869.  
  870. This routine is really just two nested loops.  The inner loop generates a
  871. raster.  The outer loop copies it to the LN03 buffer.  The outer loop is the
  872. simpler of the two, so I'll describe it first.
  873.  
  874. The outer loop has three parts.  The first is to clear the array pointed to
  875. by row_ptr.  This is used to hold generated raster.  Second is to actually
  876. generate the raster.  Lastly, it copies the generated raster to the LN03
  877. buffer once, and then N more times (as indicated by the repeat_count).
  878. The loop terminates when all rows have been processed.
  879.  
  880. The inner loop generates the raster and places it into the byte array
  881. pointed to by row_ptr.  In each through the loop (until it terminates), we
  882. can process a certain number of bits (c2).  The number is constrained by the
  883. remaining length of the run count (count), the number of bits left to add to
  884. finish the raster (width-col), and if the color is "black" the number of
  885. bits remaining in the byte.  
  886.  
  887. Since the raster was initially cleared, we can skip over all "white" bits in
  888. row as long as we account for them.  Hence, we can process multiple bytes at
  889. a time with no problem.  
  890.  
  891. If the current color is black, then we are limited to what we can do to a
  892. byte.  But since we do bit operations, we may be pointing to somewhere in
  893. the middle of byte.  So we can, at most, process eight bits at time and
  894. usually much less.  The current bit posiition in the current byte is
  895. contained in bottom three bits of the column/raster counter, col.  This is
  896. know as the bit wieght, bw.  A bit weight of 0 indicates that we are
  897. currently byte-aligned.  So if the color is black, we can process up to
  898. 8-bw bits at time, at the resulting number of bits would be set starting at
  899. bit bw.  To generate the bitmask, we simply OR BItMask[c2][bw] with the
  900. current byte.
  901.  
  902. It may be complicated, but it's fast!
  903.  
  904. This routine contains a section of code that is equivalent to pk_packed_num in
  905. PKtoPX.WEB.  The only real change from that function is that getnyb is now a C
  906. macro.  One other change is that we don't get/store our results from/in global
  907. variables, intead they are arguments to the function. 
  908.  
  909. To describe what this functions does is easy.  It returns the length of the
  910. next stream of bits.  To describe how it does is not.  For that, i refer you
  911. to PKtoPX.WEB and allow you to compare the code.
  912.  
  913. */
  914.  
  915. #ifdef vax
  916. struct    nybble_struct    {
  917.     unsigned low_nyb : 4;
  918.     unsigned high_nyb : 4;
  919.     };
  920.  
  921. #define getnyb(ptr) ((glyphptr->nybflag) ? \
  922.         (glyphptr->nybflag=0, \
  923.             (int) (((struct nybble_struct *) (ptr)++)->low_nyb)) : \
  924.         (glyphptr->nybflag=1, \
  925.             (int) (((struct nybble_struct *) (ptr))->high_nyb))  \
  926.         )
  927. #else
  928. #define getnyb(ptr) ((glyphptr->nybflag) ? \
  929.         (glyphptr->nybflag=0, (ptr)++, (ptr)[-1] & 0x0f) : \
  930.         (glyphptr->nybflag=1, *(ptr) >> 4) )
  931. #endif
  932. static void
  933. PKUnpackRasters( glyphptr )
  934. register PKGlyph *glyphptr;
  935. {
  936.     int height = glyphptr->height, width=glyphptr->width;
  937.     int color = glyphptr->color;    
  938.     unsigned char *outptr = glyphptr->rasters;
  939.     unsigned char *inptr = glyphptr->prasters;
  940.  
  941.     int bytes_per_row, row, repeat_count, count, dyn_f;
  942.     unsigned char *row_ptr, tmp_row[128];
  943. #ifdef PKDEBUG
  944.     printf("unpacking "); fflush(stdout);
  945. #endif
  946.     bytes_per_row = (width + 7) / 8;
  947.     if  (bytes_per_row > sizeof(tmp_row)) {
  948.     row_ptr = (unsigned char *) malloc( bytes_per_row );
  949.     if  (row_ptr == NULL) {
  950.         sprintf( PKerror, "can't malloc %ld byte for raster buffer", 
  951.             bytes_per_row );
  952.         return;
  953.     }
  954.     } else {
  955.     row_ptr = tmp_row;
  956.     }
  957.     color ^= 1;    /* corrected on first run count */
  958.     glyphptr->nybflag = 0;    /* start off right */
  959.     dyn_f = glyphptr->dyn_f;    /* store it locally */
  960.  
  961.     for ( row=0, count=0; row < height; row += 1 + repeat_count) {
  962.     register int col, idx;
  963.  
  964.     repeat_count = 0;
  965.     for ( col = 0; col < bytes_per_row; col++ )
  966.         row_ptr[col] = 0;
  967.  
  968.     for ( col=0; col < width; ) { 
  969.         register int c2;
  970.         if (count == 0) {
  971.         register int nyb = getnyb(inptr);
  972.         if (nyb == 0) {
  973.             register  int j;
  974.             do  {
  975.             j = getnyb(inptr);
  976.             nyb++;
  977.             }   while (j == 0);
  978.             for ( ; nyb > 0; nyb-- )
  979.             j = j*16 + getnyb(inptr);
  980.             count = j - 15 + (13 - dyn_f)*16 + dyn_f;
  981.         } else if (nyb <= dyn_f) {
  982.             count = nyb;
  983.         } else if (nyb < 14) {
  984.             count = (nyb - dyn_f - 1)*16 + getnyb(inptr) + dyn_f + 1;
  985.         } else {
  986.             if  (nyb == 14)
  987.             repeat_count = -1;  /* note that we need a repeat */
  988.             else
  989.             repeat_count = 1;   /* repeat count is 1 */
  990.             continue;        /* cycle thru and the get the count */
  991.         }
  992.         if  (repeat_count == -1)  { /* need a repeat count? */
  993.             repeat_count = count;   /*     yes, save it */
  994.             count = 0;            /*     zero the run count */
  995.             continue;            /*     and get the run count */
  996.         }
  997.         color ^= 1;        /* toggle color */
  998.         }
  999.         c2 = width - col;
  1000.         if  (count < c2)    c2 = count;
  1001.         if  (color) {
  1002.         register unsigned bw = col & 7;
  1003.         if (8-bw < c2) c2 = 8-bw;
  1004.         row_ptr[ col/8 ] |= BitMask( c2, bw ); /* mask in the btis */
  1005.         }
  1006.         col += c2;            /* increment column count */ 
  1007.         count -= c2;        /* decrement run count */
  1008.     }
  1009.  
  1010.     /*
  1011.     /*  Copy the completed raster to the output area. (N times)
  1012.     */
  1013.     for (idx = repeat_count; idx >= 0; idx--) {
  1014.         for ( col=0; col < bytes_per_row; col++ )
  1015.         *outptr++ = CopyByte(row_ptr[col]);
  1016.     }
  1017.      }
  1018.  
  1019.     if (count) {        /* consistency check */
  1020.     sprintf( PKerror, "%d extra bits after unpacking", count );
  1021.     }
  1022.     if  (bytes_per_row > sizeof(tmp_row))
  1023.     free(row_ptr);        /* free malloc'ed storage */
  1024. }
  1025.  
  1026.  
  1027.  
  1028. /* This function reads an unpacked PK raster and stores it into the LN03
  1029. font while byte/bit-reversing along the way.  It is almost identical to
  1030. copy_raster_by_bits in PKtoPX.WEB except some optimizarions have been added.
  1031.  
  1032. First, if the width happens to be a multiple of a 8 then we copy the row by
  1033. bytes instead by bit.  We use an array to unsigned char (rev_byte) to
  1034. reverse bits in the byte.  Second, we integrated the routine get_bt into
  1035. copy_pk_rasters.  This saves one function call for every bit.  On a VAX,
  1036. that is important.
  1037.  
  1038. Note that the inner loop is degenerative case of the inner loop of
  1039. unpack_raster which the count as always 1.  Also, instead of generating our
  1040. bitmasks by shifting, we use the BitMask array instead.
  1041.  
  1042. Lastly we do everything on a byte operand, not a four-byte integer.  This
  1043. maskes this code be extremely more transportable to other machines.  */
  1044.  
  1045. static void
  1046. PKCopyRasters( glyphptr )
  1047. PKGlyph    *glyphptr;
  1048. {
  1049.     register int row, ibw, idx = 0;
  1050.     int height = glyphptr->height, width = glyphptr->width;
  1051.     int bytes_per_row = (width + 7) / 8;
  1052.     register unsigned char *outptr = glyphptr->rasters;
  1053.     register unsigned char *inptr = glyphptr->prasters;
  1054.  
  1055. #ifdef PKDEBUG
  1056.     printf("copying "); fflush(stdout);
  1057. #endif
  1058.     if  ((width & 7) == 0) {    /* optimize */
  1059. #ifdef PKDEBUG
  1060.     printf( "by byte, " ); fflush(stdout);
  1061. #endif
  1062.     for ( row=bytes_per_row*height ; row > 0; row-- )
  1063.         outptr[idx++] = ReverseByte(*inptr++);
  1064.     } else {
  1065. #ifdef PKDEBUG
  1066.     printf( "by bit, " ); fflush(stdout);
  1067. #endif
  1068.     for ( row=height, ibw=7; row > 0; row-- ) {
  1069.         register int col, obw;
  1070.         register unsigned char outbyte = 0;
  1071.         for ( col=width,obw=0; col > 0; col-- ) {
  1072.  
  1073.         if  ((BitMask( 1, ibw ) & *inptr) != 0)
  1074.             outbyte |= BitMask( 1, obw );
  1075.  
  1076.         if ((obw += 1) > 7) {
  1077.             obw = 0;
  1078.             outptr[idx++] = CopyByte(outbyte);
  1079.             outbyte = 0;
  1080.         }
  1081.         if ((ibw -= 1) < 0) {
  1082.             ibw = 7;
  1083.             ++inptr;
  1084.         }
  1085.         }
  1086.         if (obw > 0) {
  1087.         obw = 0;
  1088.         outptr[idx++] = CopyByte(outbyte);
  1089.         }
  1090.     }
  1091.     }
  1092.     if  (idx != (row = height * bytes_per_row))
  1093.     sprintf( "copied wrong number [%ld] of bytes, should be %ld",idx,row);
  1094.     return;
  1095. }
  1096.  
  1097.